#pragma once
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <cassert>
#include <functional>

class Thread;
class Context
{
public:
    Thread *_this;
    void *_args;

public:
    Context() : _this(nullptr), _args(nullptr)
    {}

    ~Context() {}
};

class Thread
{
public:
    typedef std::function<void *(void *)> func_t;
    const int num = 1024;
public:
    Thread(func_t func, void *args, int number) : _func(func), _args(args)
    {
        char buffer[num];
        snprintf(buffer, sizeof(buffer), "thread-%d", number);
        _name = buffer;
    }

    void *run(void *args)
    {
        return _func(args);
    }

    //由于是类内成员函数，所以还有一个隐藏的this指针，所以要加上static修饰。
    static void *start_routine(void *args)
    {
        //将传过来的参数进行强制类型转换，就可以通过ctx这个指针访问Thread类。
        Context *ctx = static_cast<Context *>(args);
        void *ret = ctx->_this->run(ctx->_args);
        delete ctx;
        return ret;

        //静态方法不能调用成员方法或成员变量，这种返回值的方式也不行
        //return _func(args);
    }

    void start()
    {
        //由于pthread_create()是c语言接口，不支持c++的语法，所以这种方式不行
        //int n = pthread_create(&_tid, nullptr, _func, _args);

        //start_routine加上static修饰后，静态方法不能调用成员方法或成员变量
        //int n = pthread_create(&_tid, nullptr, start_routine, _args);

        //通过一个结构体来保存Thread类的this指针，就可以将这个结构体当作参数传过去，然后类内的静态函数就可以通过这个结构体访问Thread类的类内成员函数，以及变量。
        Context *ctx = new Context();
        ctx->_this = this;
        ctx->_args = _args;
        int n = pthread_create(&_tid, nullptr, start_routine, ctx);
        assert(n == 0);
        (void)n;
    }

    void join()
    {
        int n = pthread_join(_tid, nullptr);
        assert(n == 0);
        (void)n;
    }

    ~Thread()
    {
        //do nothing
    }


private:
    std::string _name;
    pthread_t _tid;
    void *_args;
    func_t _func;
};